/**
@file
Contains Buffer class.

Version: 
0.1.0

Last updated date:
2012-10-04
*/

#pragma once


namespace Zaf {

/** 
Represents a buffer allocated on heap.

The buffer's element is defined by template parameter Element.
The type of Element must have a constructor with no parameter,
and its instances are copyable.

Instances of this class is uncopyable.

This class is Uninheritable.
 */
template<typename Element>
class Buffer {

public:

	/** 
	Allocates a buffer with specified length on heap.

	@param length Count of elements.

	Content in buffer is random, if Element doesn't have constructor.
	 */
	explicit Buffer(unsigned int length) {
		Ctor(length);
	}

	/**	
	Allocates a buffer with specified length on heap,
	and fills it up with specified value.

	@param length Count of elements.
	@param value Value to fill up the buffer.
	 */
	Buffer(unsigned int length, Element value) {
		Ctor(length);
		Fill(value);
	}

	/**	
	Frees the buffer.
	 */
	~Buffer() { delete [] m_buffer; }

	/**
	Reallocates the buffer with specified length.

	@param length Count of elements.

	Original content will not be reserved. 
	Content in new buffer is random, if Element doesn't have constructor.  
	 */
	void Resize(unsigned int length) {
		DoResize(length);
	}

	/**
	Reallocates the buffer with specified length, 
	and fills it up with specified value.

	@param length Count of elements.
	@param value Value to fill up the buffer.

	Original content will not be reserved.
	 */
	void Resize(unsigned int length, Element value) {
		DoResize(length);
		Fill(value);
	}

	/**
	Fills up buffer with specified value.

	@param value Value to fill up the buffer.
	 */
	void Fill(Element value) {
		Element* pElement = m_buffer;
		while (pElement - m_buffer < m_length) {
			*pElement = value;
		}
	}

	/**
	Gets buffer's length.

	@return Element count.
	 */
	unsigned int GetLength() const { return m_length; }

	/**
	Gets pointer to buffer, modifiable.

	@return Inconstant pointer to buffer.
	 */
	Element* Get() { return m_buffer; }

	/**
	Gets pointer to buffer, unmodifiable.

	@return Constant pointer to buffer.
	 */
	const Element* Get() const { return m_buffer; }

	/**
	Converts instance to pointer to buffer, modifiable.

	@return Inconstant pointer to buffer.
	 */
	operator Element*() { return m_buffer; }

	/**
	Converts instance to pointer to buffer, unmodifiable.

	@return Constant pointer to buffer.
	 */
	operator const Element*() const { return m_buffer; }

	/**
	Gets inconstant element's value at specified position.

	@param index Position of element.
	@return Inconstant reference to element.

	Can use this method to modify element's value.

	Value of index will not be validated.
	 */
	Element& operator[](int index) { return m_buffer[(unsigned int)index]; }

	/**
	Gets constant element's value at specified position.

	@param index Position of element.
	@return Constant reference to element.

	Cannot use this method to modify element's value.

	Value of index will not be validated.
	 */
	const Element& operator[](int index) const { return m_buffer[(unsigned int)index]; }

private:
	Buffer(const Buffer&);
	const Buffer& operator=(const Buffer&);

	void Ctor(unsigned int length) {
		m_buffer = new Element[length];
		m_length = length;
	}

	void DoResize(unsigned int length) {
		delete [] m_buffer;
		m_buffer = new Element[length];
		m_length = length;
	}

	Element* m_buffer;
	unsigned int m_length;
};

}